#pragma once

#include <d3dx9.h>
#include <WTypes.h>
#include <assert.h>
#include <vector>
#include <string>
#include <map>
#include "Character_define.h"
#include "goodlinklist.h"
#include "iarchive.h"
#include "modelrcmgr.h"

using namespace std;

#define MAX_LINKCOUNT 4


struct _BoundBox 
{
	void Serial(CIArchive& ar)
	{
		ar.Serial((char*)this,sizeof(_BoundBox));
	}
	D3DXVECTOR3 m_vec3BoundBoxMin;
	D3DXVECTOR3 m_vec3BoundBoxMax;
};

typedef vector<_BoundBox> VecBoundBox;
struct _BoneAttr
{
	_BoneAttr() : head(0),size(1.0f),scale(1.0f)
	{

	}
	virtual void Serial(CIArchive& ar)
	{
		ar.Serial((char*)this,sizeof(_BoneAttr));
	}

	DWORD head;
	char version[50];
	float size;
	float scale;
};

class _ModelSocket
{
public:
	void Serial(CIArchive& ar)
	{
		ar.Serial(m_uID);
		ar.Serial(m_uParentBoneID);
		ar.Serial(m_strName);
		SERIALMATR(ar,m_TM);
		ar.Serial(m_uOldBoneID);
	}
	uint32 m_uID;
	uint32 m_uParentBoneID;
	string m_strName;
	D3DXMATRIX m_TM;

	uint32 m_uOldBoneID;//for mesh translate from old mesh.
};
class _BoneNode : public CGLLNode
{
	friend class _Bone;
	friend class CSkeletonMesh;
	friend class CModelStructTransf;
public:
	_BoneNode()	;
	~_BoneNode();
	virtual void Serial(CIArchive& ar)
	{
        ar.Serial(m_uID);
		SERIALMATR(ar,m_TM);
		ar.Serial(m_strName);
		SerialGList(ar,m_Children);

		if (ar.IsReading())
		{
			D3DXMatrixInverse(&m_matInverse,NULL,&m_TM);			
		}
	}



	uint32 GetID() const
	{
		return m_uID;
	}

	const char* GetName() const
	{
		return m_strName.c_str();
	}

	inline const D3DXMATRIX& GetMat() const
	{
		return m_TM;
	}
	inline const D3DXMATRIX& GetInvMat() const
	{
		return m_matInverse;
	}

	
protected:	
	uint32 GetTotalChildCount();
	void TotalMatInv2Array(D3DXMATRIX* pArray);

	_BoneNode* GetBoneNode(const char* szName);
	_BoneNode* GetBoneNode(const uint32& uID);	

protected:
	uint32  m_uID;
	D3DXMATRIX m_TM;
	D3DXMATRIX m_matInverse;//not save;
	CGLinkedList<_BoneNode*>	m_Children;
	string m_strName;
};

class _Bone : public CModelRCBase
{
	friend class CSkeletonMesh;
	friend class CModelStructTransf;
typedef vector<_ModelSocket> VecModelSocket;
public:
	_Bone(): m_pBoneOffsetBuf(NULL),m_pBoneInverseMat(NULL),m_uBoneCount(0)
	{
	}
	~_Bone()
	{
		GXRELEASE(m_pBoneOffsetBuf);
	}
	virtual void Serial(CIArchive& ar)
	{
		m_Attr.Serial(ar);
		ar.Serial(m_vecBoundBox,ENTITY_TYPE(_BoundBox));
		ar.Serial(m_vecSocket,ENTITY_TYPE(_ModelSocket));
		m_RootBoneNode.Serial(ar);
		
		if (ar.IsReading())
		{
			Init();
		}
	}

	inline const uint32 GetBoneCount() 
	{
		if (m_uBoneCount == 0)
		{
			m_uBoneCount = m_RootBoneNode.GetTotalChildCount() + 1;
		}
		return m_uBoneCount;
	}

	inline uint32 GetSocketCount()
	{
		return m_vecSocket.size();
	}

	_BoneNode* GetRootNode()
	{
		return &m_RootBoneNode;
	}

	inline const float GetScale() const
	{
		return m_Attr.scale;
	}

	const _BoneNode* GetBoneNode(const char* szName);
	const _BoneNode* GetBoneNode(const uint32& uID);

	const _ModelSocket* GetSocketNode(const char* szName);
	const _ModelSocket* GetSocketNode(const uint32& uID);

private:
	void Init();

protected:
	string m_strName;//not save
	_BoneAttr m_Attr;
	_BoneNode  m_RootBoneNode;
	VecBoundBox m_vecBoundBox;	
	VecModelSocket m_vecSocket;

protected:
	D3DXMATRIX*  m_pBoneInverseMat;//from m_pBoneOffsetBuf
private:
	LPD3DXBUFFER m_pBoneOffsetBuf;
	uint32 m_uBoneCount;
};


